Skip to content

feat(network-details): Implement header and body extraction#7585

Merged
43jay merged 12 commits into
mainfrom
mobile-935/extract-network-details
Apr 29, 2026
Merged

feat(network-details): Implement header and body extraction#7585
43jay merged 12 commits into
mainfrom
mobile-935/extract-network-details

Conversation

@43jay
Copy link
Copy Markdown
Contributor

@43jay 43jay commented Mar 4, 2026

📜 Description

SentryNetworkBody

Extract request/response bodies that are either JSON, formurlencoded, binary or text.

  • Relies on having a contentType to decide how to interpret the body (NSData).
  • Relies on iOS's UTType to decide whether something is JSON or text.

text:
tries .utf8 , then .isoLatin1 then gives up with BODY_PARSE_ERROR warning.

json:
tries JSONSerialization.jsonObject, gives up with BODY_PARSE_ERROR warning

UTType doesn't know:
extracts a placeholder body E.g. "[Body not captured: contentType=application/octet-stream (10240 bytes)]"

SentryReplayNetworkRequestOrResponse

  • case-insensitive header extraction

💡 Motivation and Context

See first PR in stack.

💚 How did you test it?

Unit tests

make test-ios ONLY_TESTING="SentryReplayNetworkDetailsBodyTests,SentryReplayNetworkDetailsHeaderTests,SentryReplayNetworkDetailsIntegrationTests"

Test Suite 'SentryReplayNetworkDetailsBodyTests' started at 2026-03-19 15:25:09.315.
✔ testInit_withBinaryContentType_shouldCreateArtificialString (0.005 seconds)
✔ testInit_withEmptyData_shouldReturnNil (0.000 seconds)
✔ testInit_withFormURLEncoded_duplicateKeys_shouldPromoteToArray (0.001 seconds)
✔ testInit_withFormURLEncoded_emptyKeys_shouldBeSkipped (0.000 seconds)
✔ testInit_withFormURLEncoded_emptyValue_shouldParseAsEmptyString (0.000 seconds)
Resolving Package Graph
✔ testInit_withFormURLEncoded_equalsInValue_shouldPreserve (0.000 seconds)
✔ testInit_withFormURLEncoded_missingEquals_shouldFallbackToText (0.001 seconds)
✔ testInit_withFormURLEncoded_shouldParseAsForm (0.001 seconds)
✔ testInit_withInvalidJSON_shouldFallbackToString (0.001 seconds)
✔ testInit_withJSONArray_shouldParseCorrectly (0.000 seconds)
✔ testInit_withJSONDictionary_shouldParseCorrectly (0.001 seconds)
✔ testInit_withLargeData_shouldTruncate (0.005 seconds)
✔ testInit_withNilContentType_shouldCreatePlaceholder (0.000 seconds)
✔ testInit_withTextData_shouldStoreAsString (0.000 seconds)
✔ testInit_withUnrecognizedContentType_shouldCreatePlaceholder (0.000 seconds)
✔ testParseMimeAndEncoding_shouldHandleEdgeCases (0.001 seconds)
✔ testSerialize_withJSONArray_shouldReturnArray (0.001 seconds)
✔ testSerialize_withJSONDictionary_shouldReturnDictionary (0.001 seconds)
✔ testSerialize_withNoContentType_shouldCreatePlaceholder (0.001 seconds)
✔ testSerialize_withStringBody_shouldReturnDictionary (0.001 seconds)
Executed 20 tests, with 0 failures (0 unexpected) in 0.021 (0.041) seconds
Test Suite 'SentryTests.xctest' passed at 2026-03-19 15:25:09.356.
Executed 20 tests, with 0 failures (0 unexpected) in 0.021 (0.041) seconds

SentryReplayNetworkDetailsHeaderTests (4 tests):

  • testExtractHeaders_withNilInputs_returnsEmptyDict — nil headers/config returns empty
  • testExtractHeaders_unconfiguredHeadersAreExcluded — only configured headers are extracted
  • testExtractHeaders_caseInsensitiveMatching — header matching is case-insensitive
  • testExtractHeaders_nonStringValues_convertedToStrings — non-string header values are converted

SentryReplayNetworkDetailsIntegrationTests (4 tests):

  • testInit_withMethod_shouldSetMethod — HTTP method is stored
  • testSerialize_withFullData_shouldReturnCompleteDictionary — full detail serializes all fields
  • testSerialize_withPartialData_shouldOnlyIncludeSetFields — partial data omits unset fields
  • testSerialize_withHeaderFiltering_shouldOnlyIncludeConfiguredHeaders — header filtering works end-to-end

📝 Checklist

You have to check all boxes before merging:

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled. N/A
  • I updated the docs if needed. future PR
  • I updated the wizard if needed. N/A
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog. #skip-changelog future PR
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

Closes #7710

@linear
Copy link
Copy Markdown

linear Bot commented Mar 4, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 4, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


This PR will not appear in the changelog.


🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 4, 2026

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against d0b9491

@43jay 43jay marked this pull request as ready for review March 4, 2026 04:31
Comment thread Sources/Sentry/SentryNetworkBody.m Outdated
Comment thread Sources/Sentry/SentryNetworkBody.m Outdated
Comment thread Sources/Sentry/SentryNetworkBody.m Outdated
Comment thread Sources/Sentry/SentryNetworkBodyWarning.m Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 4, 2026

Codecov Report

❌ Patch coverage is 97.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.409%. Comparing base (6baf12d) to head (d0b9491).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...ons/SessionReplay/SentryReplayNetworkDetails.swift 97.000% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #7585       +/-   ##
=============================================
+ Coverage   85.186%   85.409%   +0.223%     
=============================================
  Files          490       490               
  Lines        29520     29616       +96     
  Branches     12761     12813       +52     
=============================================
+ Hits         25147     25295      +148     
+ Misses        4322      4269       -53     
- Partials        51        52        +1     
Files with missing lines Coverage Δ
...ons/SessionReplay/SentryReplayNetworkDetails.swift 96.644% <97.000%> (+96.644%) ⬆️

... and 8 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6baf12d...d0b9491. Read the comment docs.

@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 9473efb to 5bc5830 Compare March 4, 2026 21:03
@43jay 43jay force-pushed the mobile-935/extract-network-details branch 2 times, most recently from 3547546 to e7c5abb Compare March 4, 2026 22:00
@43jay 43jay force-pushed the mobile-935/new-swizzling branch 2 times, most recently from 7faf4ef to 6e19c0a Compare March 6, 2026 16:33
@43jay 43jay force-pushed the mobile-935/extract-network-details branch from e7c5abb to 2e9607e Compare March 6, 2026 16:33
Comment thread Sources/Swift/Integrations/SessionReplay/SentryReplayNetworkDetails.swift Outdated
@43jay 43jay marked this pull request as draft March 6, 2026 18:43
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 6e19c0a to 9a8d48d Compare March 6, 2026 19:25
@43jay 43jay force-pushed the mobile-935/extract-network-details branch 2 times, most recently from 6e5c5bb to 41cf944 Compare March 9, 2026 18:09
@43jay 43jay force-pushed the mobile-935/new-swizzling branch from 9a8d48d to 8584657 Compare March 9, 2026 18:09
@43jay 43jay force-pushed the mobile-935/extract-network-details branch from 41cf944 to 68fbe88 Compare March 9, 2026 19:02
@43jay 43jay force-pushed the mobile-935/new-swizzling branch 2 times, most recently from c3afd6d to 6e873ec Compare March 9, 2026 19:48
@43jay 43jay force-pushed the mobile-935/extract-network-details branch from 68fbe88 to 6a06365 Compare March 9, 2026 19:48
@itaybre itaybre added the ready-to-merge Use this label to trigger all PR workflows label Apr 28, 2026
@sentry
Copy link
Copy Markdown

sentry Bot commented Apr 28, 2026

📲 Install Builds

iOS

🔗 App Name App ID Version Configuration
SDK-Size io.sentry.sample.SDK-Size 9.11.0 (1) Release

⚙️ sentry-cocoa Build Distribution Settings

@43jay 43jay force-pushed the mobile-935/extract-network-details branch from c73b24f to dc3a7af Compare April 28, 2026 20:58
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1228.73 ms 1248.05 ms 19.31 ms
Size 24.14 KiB 1.15 MiB 1.13 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
787537a 1218.35 ms 1251.72 ms 33.38 ms
ffb6adc 1218.60 ms 1247.47 ms 28.87 ms
b6fa517 1218.83 ms 1257.47 ms 38.63 ms
df67624 1225.12 ms 1259.90 ms 34.78 ms
a7c42d9 1217.25 ms 1253.98 ms 36.73 ms
29d546e 1224.06 ms 1257.05 ms 32.98 ms
1c5ecda 1219.35 ms 1253.76 ms 34.41 ms
ae8cece 1216.83 ms 1251.37 ms 34.55 ms

App size

Revision Plain With Sentry Diff
787537a 24.14 KiB 1.15 MiB 1.12 MiB
ffb6adc 24.14 KiB 1.15 MiB 1.12 MiB
b6fa517 24.14 KiB 1.14 MiB 1.12 MiB
df67624 24.14 KiB 1.14 MiB 1.12 MiB
a7c42d9 24.14 KiB 1.15 MiB 1.13 MiB
29d546e 24.14 KiB 1.15 MiB 1.13 MiB
1c5ecda 24.14 KiB 1.15 MiB 1.12 MiB
ae8cece 24.14 KiB 1.15 MiB 1.13 MiB

Previous results on branch: mobile-935/extract-network-details

Startup times

Revision Plain With Sentry Diff
0390710 1214.67 ms 1245.27 ms 30.60 ms
ef5b57a 1226.96 ms 1259.79 ms 32.83 ms
00b9497 1212.87 ms 1240.63 ms 27.76 ms
4a5e66b 1228.77 ms 1254.27 ms 25.50 ms

App size

Revision Plain With Sentry Diff
0390710 24.14 KiB 1.15 MiB 1.13 MiB
ef5b57a 24.14 KiB 1.15 MiB 1.12 MiB
00b9497 24.14 KiB 1.15 MiB 1.13 MiB
4a5e66b 24.14 KiB 1.15 MiB 1.13 MiB

@43jay 43jay force-pushed the mobile-935/extract-network-details branch from dc3a7af to 5372649 Compare April 28, 2026 21:40
@43jay 43jay force-pushed the mobile-935/extract-network-details branch from 5372649 to c1488f7 Compare April 28, 2026 22:19
Base automatically changed from mobile-935/new-swizzling to main April 28, 2026 23:19
@43jay 43jay force-pushed the mobile-935/extract-network-details branch from c1488f7 to 98d01fc Compare April 29, 2026 01:26
@43jay
Copy link
Copy Markdown
Contributor Author

43jay commented Apr 29, 2026

rebase on main

@43jay 43jay enabled auto-merge (squash) April 29, 2026 02:43
43jay added 12 commits April 29, 2026 06:00
1) Extracts bodies that are JSON, formurlencoded, or text.

Uses UTType to accurately classify content types as JSON
or text without maintaining a manual list. Falls back
to a string match for application/x-www-form-urlencoded
which has no UTType representation.

!Relies on having a valid `contentType`

2) Populates NetworkBodyWarning's for
 "MAYBE_JSON_TRUNCATED"
 "TEXT_TRUNCATED"
 "BODY_PARSE_ERROR"
 ^when encountered, these show custom dashboard UI.
Uses UTType to classify content types: only content positively identified
as text is decoded. Everything else gets a descriptive placeholder:
 Example - "[Body not captured: contentType=image/png (8 bytes)]"

Known text types (where UTType conforms to .text) are reliably classified
by UTType's type hierarchy. If a content type header is incorrect (e.g.
claims text but contains binary), the resulting decode failure is caught
by the existing bodyParseError warning.
UTType (UniformTypeIdentifiers) requires macOS 11+, but the SDK
targets macOS 10.14. Extract UTType-based MIME detection into a
separate method gated with @available(macOS 11, *) so the code
compiles on all macOS targets. Session Replay is not available on
macOS, so the fallback placeholder is fine.
Casts to lower-case before comparing headers.
ObjC setters now accept raw allHeaders and configuredHeaders instead
of pre-filtered headers, keeping the filtering logic in Swift.
#7585 (comment)

Parse MIME type and charset from Content-Type using
CFStringConvertIANACharSetNameToEncoding instead of
hardcoding UTF-8/ISO-Latin-1 fallbacks.
Replace force-unwraps and if-let/XCTFail patterns in
SentryReplayNetworkDetailsBodyTests with XCTUnwrap for optional
casts and Data(_:) for String-to-Data conversions.
@43jay 43jay force-pushed the mobile-935/extract-network-details branch from 98d01fc to d0b9491 Compare April 29, 2026 10:00
@43jay 43jay merged commit e44b6f8 into main Apr 29, 2026
212 of 216 checks passed
@43jay 43jay deleted the mobile-935/extract-network-details branch April 29, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Use this label to trigger all PR workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(network-details): Implement header and body extraction

3 participants